﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Data.Entity;
using System.Linq;
using yiCommerce.Core.Data;
using yiCommerce.Core.Domain.Pictures;
using yiCommerce.Core.Domain.Products;

namespace yiCommerce.Service.Products
{
    public class ProductService:IProductService
    {
        private IRepository<Product> _productRepository;
        private IRepository<ProductVariant> _productVariantRepository;
        private IRepository<ProductAttribute> _productAttributeRepository;
        private IRepository<ProductVariantAttribute> _productVariantAttributeRepository;
        private IRepository<ProductVariantAttributeValue> _productVariantAttributeValueRepository;
        private IRepository<SpecificationAttribute> _spRepository;
        private IRepository<SpecificationAttributeOption> _spOptionRepository;
        private IRepository<Picture> _picRepository;
        private IRepository<ProductPicture> _productPictureRepository;

        public ProductService(IRepository<Product> productRepository, IRepository<ProductVariant> productVariantRepository, IRepository<ProductAttribute> productAttributeRepository, IRepository<SpecificationAttribute> spRepository, IRepository<Picture> picRepository, IRepository<SpecificationAttributeOption> spOptionRepository, IRepository<ProductVariantAttribute> productVariantAttributeRepository, IRepository<ProductVariantAttributeValue> productVariantAttributeValueRepository, IRepository<ProductPicture> productPictureRepository)
        {
            _productRepository = productRepository;
            _productVariantRepository = productVariantRepository;
            _productAttributeRepository = productAttributeRepository;
            _spRepository = spRepository;
            _picRepository = picRepository;
            _spOptionRepository = spOptionRepository;
            _productVariantAttributeRepository = productVariantAttributeRepository;
            _productVariantAttributeValueRepository = productVariantAttributeValueRepository;
            _productPictureRepository = productPictureRepository;
        }

        public void DeleteProduct(Product product)
        {
            throw new System.NotImplementedException();
        }

        public IList<Product> GetAllProducts()
        {
            throw new System.NotImplementedException();
        }

        public IList<Product> GetAllProductsByShopPid(int shopId)
        {

            var query = from s in _productRepository.Table
                        where s.ShopId==shopId 
                        select s;

            var p = query.ToList();
            if (p != null)
            {

                return ProductMapper.ToProducts(p);
            }
            else
            {
                return null;
            }
        }

        public void DeleteProduct(int productId)
        {
            var query = from s in _productRepository.Table
                        where s.Id == productId
                        select s;

            var p = query.SingleOrDefault();
            if (p != null)
            {

                p.Deleted = true;

            }
        }

        public Product GetProductById(int productId)
        {
            var query = from s in _productRepository.Table
                        where s.Id ==productId
                        select s;

            var p = query.SingleOrDefault();
            if (p != null)
            {

                return ProductMapper.ToProduct(p);

                
            }
            else
            {
                return null;
            }

        }

     

        public void InsertProduct(Product product)
        {
            throw new System.NotImplementedException();
        }

        public void UpdateProduct(Product product)
        {
            throw new System.NotImplementedException();
        }

        public ProductInfoInsertResult InsertProductInfo(ProductInfoInsertRequest productInfoInsertRequest)
        {
            var result = new ProductInfoInsertResult();

            try
            {
                var p = new Product();
                p.ShopId = productInfoInsertRequest.ShopId;
                p.ProductName = productInfoInsertRequest.ProductName;
                p.ShortDescription = productInfoInsertRequest.ShortDescription;
                p.FullDescription = productInfoInsertRequest.FullDescription;
                p.Published = productInfoInsertRequest.IsPublished;
                p.Deleted = false;
                p.CreatedOnUtc = DateTime.Now;
                p.UpdatedOnUtc = DateTime.Now;

                _productRepository.Insert(p);

                result.Id = p.Id;

                var pv = new ProductVariant();

                pv.ProductId = p.Id;

                pv.PictureId = productInfoInsertRequest.PictureIds[0];
                pv.Published = productInfoInsertRequest.IsPublished;
                pv.DisplayOrder = 1;
                pv.StockQuantity = productInfoInsertRequest.StockQuantity;
                pv.Price = productInfoInsertRequest.Price;
                pv.CreatedOnUtc = DateTime.Now;
                pv.UpdatedOnUtc = DateTime.Now;
                _productVariantRepository.Insert(pv);


                foreach (var picId in productInfoInsertRequest.PictureIds)
                {
                    var pp = new ProductPicture()
                    {
                        PictureId = picId,
                        ProductId = p.Id
                    };
                    _productPictureRepository.Insert(pp);
                }
               
            }
            catch (Exception e)
            {
                result.AddError(e.Message);
            }
            return result;
        }

        public ProductInfoUpdateResult UpdateProductInfo(ProductInfoUpdateRequest productInfoUpdateRequest)
        {
            var result = new ProductInfoUpdateResult();

            try
            {

                var p = _productRepository.GetById(productInfoUpdateRequest.Id);
                if (p == null)
                {
                    throw new Exception("product not exist");
                }

                p.ProductName = productInfoUpdateRequest.ProductName;
                p.ShortDescription = productInfoUpdateRequest.ShortDescription;
                p.FullDescription = productInfoUpdateRequest.FullDescription;
                p.Published = productInfoUpdateRequest.IsPublished;

                _productRepository.Update(p);
           
            }
            catch (Exception e)
            {
                result.AddError(e.Message);
            } 
            return result;
        }

        public ProductVariant GetProductVariantById(int productVariantId)
        {
            var query = from s in _productVariantRepository.Table
                        where s.Id == productVariantId
                        select s;

            var p = query.SingleOrDefault();
            if (p != null)
            {

                return ProductMapper.ToProductVariant(p);
            }
            else
            {
                return null;
            }
        }

       

        public ProductVariant GetProductVariantBySku(string sku)
        {
            throw new System.NotImplementedException();
        }

        public int InsertProductVariantInfo(int productId, string name, string sku, decimal price, int displayOrder, int stockQuantity, int pictureId,
                                            bool published)
        {
            var pv = new ProductVariant()
                {
                    Name = name,
                    Sku = sku,
                    Price = price,
                    DisplayOrder = displayOrder,
                    StockQuantity = stockQuantity,
                    PictureId = pictureId,
                    Published = published,
                    CreatedOnUtc = DateTime.Now,
                    UpdatedOnUtc = DateTime.Now,
                    ProductId = productId,
                };

            _productVariantRepository.Insert(pv);
            return pv.Id;

        }

        public void UpdateProductVariantInfo(int productVariantId, string name, string sku, decimal price, int displayOrder,
                                             int stockQuantity, int pictureId, bool published)
        {
            var pv = _productVariantRepository.GetById(productVariantId);
            pv.Name = name;
            pv.Sku = sku;
            pv.Price = price;
            pv.DisplayOrder = displayOrder;
            pv.StockQuantity = stockQuantity;
            pv.PictureId = pictureId;
            pv.Published = published;
            _productVariantRepository.Update(pv);
        }

        public void InsertProductVariant(ProductVariant productVariant)
        {
            throw new System.NotImplementedException();
        }

        public void UpdateProductVariant(ProductVariant productVariant)
        {
            if (productVariant == null)
                throw new ArgumentNullException("productVariant");

            _productVariantRepository.Update(productVariant);
        }

        public IList<ProductVariant> GetProductVariantsByProductId(int productId)
        {
            throw new System.NotImplementedException();
        }

        public void DeleteProductVariant(ProductVariant productVariant)
        {
            throw new System.NotImplementedException();
        }

        public void AdjustInventory(ProductVariant productVariant, bool decrease, int quantity, string attributesXml)
        {
            if (productVariant == null)
                throw new ArgumentNullException("productVariant");


            int newStockQuantity = 0;
            if (decrease)
                newStockQuantity = productVariant.StockQuantity - quantity;
            else
                newStockQuantity = productVariant.StockQuantity + quantity;


            productVariant.StockQuantity = newStockQuantity;
           

            UpdateProductVariant(productVariant);
        }

        public IList<ProductAttribute> GetAllProductAttributes()
        {
            return _productAttributeRepository.Table.ToList();
        }

        public int InsertProductVariantAttribute(int pvId, AttributeControlType selectedAttributeType, int selectedProductAttributeId)
        {
            var p = new ProductVariantAttribute()
            {
                ProductVariantId = pvId,
                AttributeControlType = selectedAttributeType,
                ProductAttributeId =  selectedProductAttributeId,
            };
            _productVariantAttributeRepository.Insert(p);
            return p.Id;
        }

        public IList<SpecificationAttribute> GetAllSpecificationAttribute()
        {
            var query = _spRepository.Table;

            var p = query.ToList();
            if ( p!= null)
            {

                return p.Select(c=> new SpecificationAttribute()
                {
                    Id = c.Id,

                    Name = c.Name,
                    DisplayOrder = c.DisplayOrder,

                    SpecificationAttributeOptions = c.SpecificationAttributeOptions.Select(t=>new SpecificationAttributeOption()
                        {
                            Id = t.Id,
                            Name = t.Name
                        }).ToList()
                }).ToList();
            }
            else
            {
                return null;
            }
        }

        public void InsertProductSpecificationAttribute(int productId, int specificationAttributeOptionId)
        {
            var p = _productRepository.GetById(productId);
            var spo = _spOptionRepository.GetById(specificationAttributeOptionId);
            var ps = new ProductSpecificationAttribute()
                {
                    Product = p,
                    SpecificationAttributeOption = spo,
                };

            p.ProductSpecificationAttributes.Clear();
            p.ProductSpecificationAttributes.Add(ps);
            _productRepository.Update(p);
        }

        public int InsertProductPicture(int productId, int pictureId, int displayOrder)
        {

            var p = new ProductPicture()
                {
                    DisplayOrder = displayOrder,
                    PictureId = pictureId,
                    ProductId = productId
                };
            _productPictureRepository.Insert(p);

            return p.Id;
            //var p = _productRepository.GetById(productId);
            //p.ProductPictures.Add(new ProductPicture()
            //    {
            //        PictureId = pictureId,
            //        ProductId = productId,
            //        DisplayOrder = displayOrder,

            //    });
            //_productRepository.Update(p);


        }

        public IList<ProductVariantAttribute> GetProductVariantAttributesByProductVariantId(int productVariantId)
        {
            var pv = this.GetProductVariantById(productVariantId);
            if (pv != null)
            {
                return pv.ProductVariantAttributes.ToList();
            }

            else
            {
                throw  new Exception(string.Format("product variant id: {0} not exist", productVariantId));
            }

        }

        public ProductVariantAttribute GetProductVariantAttributeByProductVariantAttributeId(int productVariantAttributeId)
        {
            var pva =  _productVariantAttributeRepository.GetById(productVariantAttributeId);

            if (pva != null)
            {
                return new ProductVariantAttribute()
                    {
                        ProductVariantId = pva.ProductVariantId,
                        ProductAttribute = new ProductAttribute()
                            {
                                Name = pva.ProductAttribute.Name
                            },

                        ProductVariantAttributeValues =
                            pva.ProductVariantAttributeValues == null
                                ? new List<ProductVariantAttributeValue>()
                                : pva.ProductVariantAttributeValues.Select(t => new ProductVariantAttributeValue()
                                    {
                                        Name = t.Name,
                                        DisplayOrder = t.DisplayOrder
                                    }).OrderBy(c=>c.DisplayOrder).ToList()
                    };
            }
            return null;
        }

        public int InsertProductVariantAttributeValue(int productVariantAttributeId, string productVariantAttributeValue, int displayOrder)
        {
            var pvav = new ProductVariantAttributeValue()
                {
                    DisplayOrder = displayOrder,
                    Name = productVariantAttributeValue,
                    ProductVariantAttributeId = productVariantAttributeId
                };
            _productVariantAttributeValueRepository.Insert(pvav);
            return pvav.Id;
        }

        public ProductVariantAttributeValue GetProductVariantAttributeValueByProductVariantAttributeValueId(
            int productVariantAttributeValueId)
        {

            var query = from pv in _productVariantAttributeValueRepository.Table
                        where pv.Id == productVariantAttributeValueId
                        select pv;

            var p = query.SingleOrDefault();
            if (p != null)
            {
                return new ProductVariantAttributeValue()
                    {
                        Id = p.Id,
                        Name = p.Name,
                        ProductVariantAttribute = new ProductVariantAttribute()
                            {
                                ProductAttribute = new ProductAttribute()
                                    {
                                        Name = p.ProductVariantAttribute.ProductAttribute.Name
                                    }
                            }

                    };
            }

            return null;

        }

        public void DeleteProductVaraintAttribute(int productvariantattributeId)
        {
            var query = from pv in _productVariantAttributeRepository.Table
                        where pv.Id == productvariantattributeId
                        select pv;

            var p = query.SingleOrDefault();
            if (p != null)
            {
                _productVariantAttributeRepository.Delete(p);
            }
        }

        public void DeleteProductVaraint(int productVariantId)
        {
            var query = from p in _productVariantRepository.Table
                        where p.Id == productVariantId
                        select p;

            var pv = query.SingleOrDefault();
            if (pv != null)
            {

                var product = pv.Product;
                if (product != null)
                {
                    if (product.ProductVariants.Count > 1)
                    {
                        pv.Deleted = true;
                        _productVariantRepository.Update(pv);
                    }
                    else
                    {
                        throw  new Exception("could not delete last product variant");
                    }
                }
            }

        }

        public void DeleteProductVaraintAttributeValue(int productvariantattributeValueId)
        {
            var query = from pva in _productVariantAttributeValueRepository.Table
                        where pva.Id == productvariantattributeValueId
                        select pva;

            var result = query.SingleOrDefault();
            if (result != null)
            {
                _productVariantAttributeValueRepository.Delete(result);
            }
        }

        public void DeleteProductPicture(int productPictureId)
        {
            var query = from pp in _productPictureRepository.Table
                        where pp.Id == productPictureId
                        select pp;
            var pobject = query.SingleOrDefault();
            if (pobject != null)
            {
                _productPictureRepository.Delete(pobject);
            }
        }
    }
}